package com.linghang.wusthelper.service.Impl;

import com.auth0.jwt.JWT;
import com.github.pagehelper.PageHelper;
import com.linghang.wusthelper.common.ServerResponse;
import com.linghang.wusthelper.common.URLConst;
import com.linghang.wusthelper.dao.primary.AnnouncementDao;
import com.linghang.wusthelper.dao.primary.CreditStatisticsDao;
import com.linghang.wusthelper.dao.primary.GradeDao;
import com.linghang.wusthelper.dao.primary.StudentDao;
import com.linghang.wusthelper.entity.primary.Announcement;
import com.linghang.wusthelper.entity.primary.CourseInfo;
import com.linghang.wusthelper.entity.primary.Grade;
import com.linghang.wusthelper.entity.primary.Student;
import com.linghang.wusthelper.redis.RedisService;
import com.linghang.wusthelper.service.JwcService;
import com.linghang.wusthelper.spider.jwc.*;
import com.linghang.wusthelper.util.EncryptUtil;
import com.linghang.wusthelper.util.JWTUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import us.codecraft.webmagic.Spider;

import java.util.*;

/**
 * @author origin
 * 教务处service实现类
 */
@Service("JwcService")
public class JwcServiceImpl implements JwcService {

    private Logger log = LoggerFactory.getLogger(getClass());

    @Autowired
    private AnnouncementDao announcementDao;

    @Autowired
    private CreditStatisticsDao creditStatisticsDao;

    @Autowired
    private GradeDao gradeDao;

    @Autowired
    private StudentDao studentDao;

    @Autowired
    private RedisService redisService;


    /**
     * 教务处登陆
     *
     * @param stuNum
     * @param passwrod
     * @return JWTtoken 用于无状态登陆
     */
    @Override
    public ServerResponse login(String stuNum, String passwrod) {
        redisService.remove(stuNum+":JSESSIONID");
        Map<String, String> resultMap = JwcSimLogin.login(stuNum, passwrod);
        if (resultMap.get("code").equals("0")) {
            log.error("教务处无法访问");
            //  教务处无法访问
            return ServerResponse.createByJWCError();
        } else if (resultMap.get("code").equals("2")) {
            //  密码错误或账号不存在
            return ServerResponse.createByErrorMsg(resultMap.get("errorMsg"));
        } else {
            //  对密码进行对称加密
            String encryptPasswpord = EncryptUtil.encryptPasswd(passwrod);
            //  检查数据库是否已经存在该学生
            Student oldStudent = studentDao.selectByStuNum(stuNum);
            if (oldStudent != null) {
                //  检查教务处密码是否已经更改
                if (!oldStudent.getJwcPassword().equals(encryptPasswpord)) {
                    studentDao.updateJWCPassword(stuNum, encryptPasswpord);
                }
                //  再次登陆清除无效UUID,生成新的UUID
                oldStudent.setUUID(UUID.randomUUID().toString());
                studentDao.updateUUID(stuNum, oldStudent.getUUID());
                //  生成token
                String token = JWTUtil.createToken(oldStudent);
                return ServerResponse.createBySuccess("登录成功", token);
            }
            Student newStudent = new Student();
            newStudent.setStuNum(stuNum);
            newStudent.setJwcPassword(encryptPasswpord);
            newStudent.setUUID(UUID.randomUUID().toString());  // 生成UUID,用于生成JWT签名
            studentDao.insertNewStu(newStudent.getStuNum(), newStudent.getJwcPassword(), newStudent.getUUID());  // 存入数据库
            //  获取学生信息
            Spider.create(new StuInfoSpider(resultMap.get("JSESSIONID"), resultMap.get("SERVERID"), studentDao,"")).addUrl(URLConst.STUDENTINFOURL).thread(1).runAsync();
            String token = JWTUtil.createToken(newStudent);
            return ServerResponse.createBySuccess("登录成功", token);
        }
    }

    /**
     * 获取成绩
     *
     * @param token
     * @return
     */
    @Override
    public ServerResponse getGrade(String token) throws InterruptedException {
        String stuNum = JWT.decode(token).getClaim("stuNum").asString();
        Student student = studentDao.selectByStuNum(stuNum);
        Map<String, String> resultMap = JwcSimLogin.login(student.getStuNum(), EncryptUtil.decryptPasswd(student.getJwcPassword()));
        if (resultMap.get("code").equals("0")) {
            List<Grade> gradeList = gradeDao.selectGradeByStu(student.getStuNum());
            return ServerResponse.createByJWCError(gradeList);
        } else if (resultMap.get("code").equals("2")) {
            return ServerResponse.createByErrorMsg("你的教务处密码已更改，请注销后重新登录");
        } else {
            String lock = new String("");
            //  异步爬取
            Spider.create(new GradeSpider(resultMap.get("JSESSIONID"), resultMap.get("SERVERID"), gradeDao, redisService, lock))
                    .addUrl(URLConst.GRADEURL)
                    .thread(1)
                    .runAsync();
            //  等待爬取完成
            synchronized (lock) {
                lock.wait();
            }
            List<Grade> gradeList = gradeDao.selectGradeByStu(student.getStuNum());
            return ServerResponse.createBySuccess("获取成功", gradeList);
        }
    }

    /**
     * 获取学分统计
     *
     * @param token
     * @return
     */
    @Override
    public ServerResponse getCredit(String token) throws InterruptedException {
        String stuNum = JWT.decode(token).getClaim("stuNum").asString();
        Student student = studentDao.selectByStuNum(stuNum);
        Map<String, String> resultMap = JwcSimLogin.login(student.getStuNum(), EncryptUtil.decryptPasswd(student.getJwcPassword()));
        if (resultMap.get("code").equals("0")) {
            String creditStatistic = creditStatisticsDao.selectByStuNum(student.getStuNum());
            return ServerResponse.createByJWCError(creditStatistic);
        } else if (resultMap.get("code").equals("2")) {
            return ServerResponse.createByErrorMsg("你的教务处密码已更改，请注销后重新登录");
        } else {
            String lock = new String("");
            Spider.create(new CreditStatisticSpider(resultMap.get("JSESSIONID"), resultMap.get("SERVERID"), stuNum, creditStatisticsDao, lock))
                    .addUrl(URLConst.CREDITSTATISTICURL)
                    .thread(1)
                    .runAsync();
            synchronized (lock) {
                lock.wait();
            }
            String creditStatistic = creditStatisticsDao.selectByStuNum(stuNum);
            return ServerResponse.createBySuccess("获取学分统计成功", creditStatistic);
        }
    }

    /**
     * 获取课表
     * @param token
     * @param schoolTerm
     * @return
     */
    @Override
    public ServerResponse getCurriculum(String token, String schoolTerm) throws InterruptedException {
        String stuNum = JWT.decode(token).getClaim("stuNum").asString();
        Student student = studentDao.selectByStuNum(stuNum);
        Map<String, String> resultMap = JwcSimLogin.login(student.getStuNum(), EncryptUtil.decryptPasswd(student.getJwcPassword()));
        if (resultMap.get("code").equals("0")) {
            return ServerResponse.createByJWCError();
        } else if (resultMap.get("code").equals("2")) {
            return ServerResponse.createByErrorMsg("你的教务处密码已更改，请注销后重新登录");
        } else {
            List<CourseInfo> courseInfoList = new ArrayList<>();
            String lock = new String("");
            Spider.create(new CurriculumSpider(resultMap.get("JSESSIONID"), resultMap.get("SERVERID"), courseInfoList, lock))
                    .addUrl(URLConst.CURRICULUMURL + "xnxqh=" + schoolTerm + "&xs0101id=" + student.getStuNum())
                    .thread(1)
                    .runAsync();
            synchronized (lock) {
                lock.wait();
            }
            return ServerResponse.createBySuccess("获取课表成功", courseInfoList);
        }
    }

    /**
     * 获取学生信息
     *
     * @param token
     * @return
     */
    @Override
    public ServerResponse getStudentInfo(String token) {
        String stuNum = JWT.decode(token).getClaim("stuNum").asString();
        Student student = studentDao.selectByStuNum(stuNum);
        //todo  将敏感信息设置为空
        student.setJwcPassword("");
        student.setLibPassword("");
        student.setUUID("");
        return ServerResponse.createBySuccess("获取学生信息成功", student);
    }

    /**
     * 更新学生信息
     * @param token
     * @return
     * @throws InterruptedException
     */
    @Override
    public ServerResponse updateStudentInfo(String token) throws InterruptedException {
        String stuNum = JWT.decode(token).getClaim("stuNum").asString();
        Student student = studentDao.selectByStuNum(stuNum);
        Map<String, String> resultMap = JwcSimLogin.login(student.getStuNum(), EncryptUtil.decryptPasswd(student.getJwcPassword()));
        if (resultMap.get("code").equals("0")) {
            return ServerResponse.createByJWCError();
        } else if (resultMap.get("code").equals("2")) {
            return ServerResponse.createByErrorMsg("你的教务处密码已更改，请注销后重新登录");
        } else {
            String lock = new String("");
            Spider.create(new StuInfoSpider(resultMap.get("JSESSIONID"), resultMap.get("SERVERID"), studentDao, lock))
                    .addUrl(URLConst.STUDENTINFOURL)
                    .thread(1)
                    .runAsync();
            synchronized (lock) {
                lock.wait();
            }
            Student studentinfo = studentDao.selectByStuNum(stuNum);
            return ServerResponse.createBySuccess("更新学生信息成功", studentinfo);
        }

    }

    /**
     * 获取教务处公告
     * @param pageNum
     * @param pageSize
     * @return
     */
    @Override
    public ServerResponse getAnnouncementList(int pageNum, int pageSize) {
        PageHelper.startPage(pageNum, pageSize);
        List<Announcement> announcementList = announcementDao.selectList();
        return ServerResponse.createBySuccess("获取公告成功", announcementList);
    }

    /**
     * 获取公告内容
     * @param announcementId
     * @return
     */
    @Override
    public ServerResponse getAnnouncementContent(int announcementId) {
        String content = announcementDao.getContent(announcementId);
        return ServerResponse.createBySuccess("获取公告内容成功",content);
    }

    /**
     * 获取分享课表
     * @param content
     * @return
     */
    @Override
    public ServerResponse getShareCurriculum(String content) {
        try {
            content = content.replaceAll(" ","+");
            String result = EncryptUtil.aesDecryptByBytes(content);
            String[] str = result.split(",");
            Student student = studentDao.selectByStuNum(str[0]);
            Map<String,String> resultMap = JwcSimLogin.login(student.getStuNum(),EncryptUtil.decryptPasswd(student.getJwcPassword()));
            if (resultMap.get("code").equals("0")) {
                return ServerResponse.createByJWCError();
            } else if (resultMap.get("code").equals("2")) {
                return ServerResponse.createByErrorMsg("你的教务处密码已更改，请注销后重新登录");
            } else{
                List<CourseInfo> courseInfoList = new ArrayList<>();
                String lock = new String("");
                Spider.create(new CurriculumSpider(resultMap.get("JSESSIONID"), resultMap.get("SERVERID"), courseInfoList, lock))
                        .addUrl(URLConst.CURRICULUMURL + "xnxqh=" + str[1] + "&xs0101id=" + student.getStuNum())
                        .thread(1)
                        .runAsync();
                synchronized (lock) {
                    lock.wait();
                }
                HashMap map = new HashMap();
                map.put("stuName",student.getStuName());
                map.put("cuuriculum",courseInfoList);
                return ServerResponse.createBySuccess("获取成功",map);
            }
        } catch (Exception e) {
            e.printStackTrace();
            log.error("无效分享课表content");
            return ServerResponse.createByErrorMsg("二维码无效");
        }
    }
}
